package com.pakaroid.android.app;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

import com.pakaroid.android.app.utils.Consts;

public class PakaroidActivity extends Activity {

    private static final String TAG = "PakaroidActivity";

    private static final int MENU_SELECT_APPS = Menu.FIRST + 1;
    private static final int MENU_SETTINGS = MENU_SELECT_APPS + 1;
	
    private ArrayList<ApplicationInfo> mLaunchApps;

    private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();
    private final BroadcastReceiver mBatteryChangeReceiver = new BatteryIntentReceiver();
    private final BroadcastReceiver mBatteryPluggedReceiver = new BatteryPluggedIntentReceiver();

    private ArrayList<String> mPackageNames;

    private GridView mGrid;
    private ViewGroup mWidgetContainer;

    private boolean mBlockAnimation;
    private boolean mBlockAnimation2;
    private boolean mUpdateLaunchApps = false;
    private boolean mIsPlugged = false;

    private View mShowAppBtn;
    private View mShowWidgetBtn;
    private ImageView mBatteryImage;
    private ImageView mBatteryText;
    private ImageView mBatteryPluggedImage;

    private Animation mGridEntry;
    private Animation mGridExit;   

    private Animation mTranslateEntry;
    private Animation mTranslateExit;   

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);

        setContentView(R.layout.main);

        mGrid = (GridView) findViewById(R.id.all_apps);
        mGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View v, int position,
					long id) {
                ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
                startActivity(app.intent);
			}
		});
        
        mShowAppBtn = findViewById(R.id.show_apps);
        mShowAppBtn.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
	            if (mGrid.getVisibility() != View.VISIBLE) {
	                showApplications(true);
	            } else {
	                hideApplications();
	            }				
			}
		});
        
        ShowWidget showWidget = new ShowWidget();
        SwitchWidget switchWidget = new SwitchWidget(this);
        
        mWidgetContainer = (ViewGroup) findViewById(R.id.widgets_container);
        mWidgetContainer.setOnClickListener(showWidget);
        
        mShowWidgetBtn = findViewById(R.id.show_widgets);
        mShowWidgetBtn.setOnClickListener(showWidget);

        mBatteryImage = (ImageView) findViewById(R.id.battery_image);
        mBatteryText = (ImageView) findViewById(R.id.battery_text);
        mBatteryPluggedImage = (ImageView) findViewById(R.id.battery_charge);
                
        registerIntentReceivers();

        mGridEntry = AnimationUtils.loadAnimation(this, R.anim.grid_entry);
        mGridExit = AnimationUtils.loadAnimation(this, R.anim.grid_exit);

        mTranslateEntry = AnimationUtils.loadAnimation(this, R.anim.translate_in);
        mTranslateExit = AnimationUtils.loadAnimation(this, R.anim.translate_out);
        
        CheckBox wifiCheckBox = (CheckBox)findViewById(R.id.widgets_wifi);
        wifiCheckBox.setOnCheckedChangeListener(switchWidget);
        wifiCheckBox.setChecked(SwitchWidget.isWiFiOn(this));

        CheckBox brightnessCheckBox = (CheckBox)findViewById(R.id.widgets_brightness);
        brightnessCheckBox.setOnCheckedChangeListener(switchWidget);
        brightnessCheckBox.setChecked(SwitchWidget.isBrightnessOn(this));

        CheckBox rotationCheckBox = (CheckBox)findViewById(R.id.widgets_rotation);
        rotationCheckBox.setOnCheckedChangeListener(switchWidget);
        rotationCheckBox.setChecked(SwitchWidget.isRotationOn(this));

        CheckBox mannerCheckBox = (CheckBox)findViewById(R.id.widgets_manner);
        mannerCheckBox.setOnCheckedChangeListener(switchWidget);
        mannerCheckBox.setChecked(SwitchWidget.isMannerOn(this));
       
        LoadAppTask task = new LoadAppTask();
        task.execute();
	}	
	
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        menu.add(0, MENU_SELECT_APPS, 0, R.string.menu_select_apps)
        		.setIcon(android.R.drawable.ic_menu_preferences);

        menu.add(0, MENU_SETTINGS, 0, R.string.menu_settings)
                .setIcon(android.R.drawable.ic_menu_preferences)
                .setIntent(new Intent(android.provider.Settings.ACTION_SETTINGS));

        return true;
    }
	
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_SELECT_APPS:
            	mUpdateLaunchApps = true;
            	Intent intent =  new Intent(new Intent(this, SettingActivity.class));
            	startActivity(intent);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

    	Log.d(TAG, "onNewIntent");

    	// Close the menu
        if (Intent.ACTION_MAIN.equals(intent.getAction())) {
            getWindow().closeAllPanels();
        }
    }
    
    @Override
    protected void onResume() {
    	super.onResume();
    	
    	if(mUpdateLaunchApps) {
    		mUpdateLaunchApps = false;
            LoadAppTask task = new LoadAppTask();
            task.execute();
    	}
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();

        // Remove the callback for the cached drawables or we leak
        // the previous Home screen on orientation change
        final int count = mLaunchApps.size();
        for (int i = 0; i < count; i++) {
            mLaunchApps.get(i).icon.setCallback(null);
        }

        unregisterReceiver(mApplicationsReceiver);
        unregisterReceiver(mBatteryChangeReceiver);
        unregisterReceiver(mBatteryPluggedReceiver);
    }
	
	public class LoadAppTask extends AsyncTask<Void, Void, Void> {

		@Override
		protected Void doInBackground(Void... params) {
	        loadApplications(true);
	        return null;
		}
	 
	    @Override
	    protected void onPostExecute(Void param) {
	        bindApplications();
	    	(findViewById(R.id.progress)).setVisibility(View.GONE);
	    }
	}	
    
    /**
     * broadcast receiver を登録
     */
    private void registerIntentReceivers() {
        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addDataScheme("package");
        registerReceiver(mApplicationsReceiver, filter);
        
        filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(mBatteryChangeReceiver, filter);
        
        filter = new IntentFilter();
		filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        filter.addAction(Intent.ACTION_BATTERY_LOW);
        filter.addAction(Intent.ACTION_BATTERY_OKAY);
        filter.addAction(Intent.ACTION_POWER_CONNECTED);
        registerReceiver(mBatteryPluggedReceiver, filter);
    }
	
    /**
     * アプリケーションのインストール・アンインストール時の処理
     */
    private class ApplicationsIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            loadApplications(false);
            bindApplications();
        }
    }
    
    /**
     * バッテリー状態変化時の処理
     */
    private class BatteryIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            
            int imageLevel = level * Consts.MAX_BATTERY_LEVEL / scale;
            
            Log.d("BatteryManager", "imageLevel = " + imageLevel);

            if(imageLevel < 0)
            	imageLevel = 0;
            
            if(imageLevel > Consts.MAX_BATTERY_LEVEL)
            	imageLevel = Consts.MAX_BATTERY_LEVEL;
            
            mBatteryImage.setImageLevel(imageLevel);
            mBatteryText.setImageLevel(imageLevel);
        }
    };
    
    /**
     * 電源抜き差し時の処理
     */
    private class BatteryPluggedIntentReceiver extends BroadcastReceiver {
    	
        @Override
        public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
				// 電源が接続されたかどうか
				mIsPlugged = intent.getIntExtra("plugged", 0) != 0;
				boolean isEmpty = false;
				
				if(mGrid != null) {
					if(mGrid.getAdapter() != null) {
				        if(mGrid.getAdapter().isEmpty()) {
				        	isEmpty = true;
						}						
					}
				}
				if(isEmpty) {
					mShowAppBtn.setBackgroundResource(R.drawable.show_app_start_stateful);
				}
				else {
					if(mIsPlugged) {
						mShowAppBtn.setBackgroundResource(R.drawable.show_app_charge_stateful);
					}
					else {
						mShowAppBtn.setBackgroundResource(R.drawable.show_app_stateful);						
					}
				}

				if(mIsPlugged) {
					mBatteryPluggedImage.setImageResource(R.drawable.rainycloud);
					mBatteryText.setImageResource(R.drawable.battery_charge_text);
				}
				else {
					mBatteryPluggedImage.setImageResource(R.drawable.cloud);
					mBatteryText.setImageResource(R.drawable.battery_text);
				}
			}
        }
    };

    /**
     * 選択されたアプリをインストールされているアプリから取得
     */
    private void loadApplications(boolean isLaunching) {
    	mPackageNames = new ArrayList<String>();
    	mLaunchApps = new ArrayList<ApplicationInfo>();
    	    	
    	ArrayList<Integer> mPackageNamePositions = new ArrayList<Integer>();
    	
        SharedPreferences prefs = getSharedPreferences(Consts.PREFS_NAME, MODE_PRIVATE);
        for(int i = 0; i < Consts.MAX_APP_NUM; i++){
//        	String packageName = prefs.getString(Consts.PREF_PREFIX_KEY + i, null);
//        	if(packageName != null) {
//        		mPackageNames.add(packageName);
//        	}
        	int position = prefs.getInt(Consts.PREF_PREFIX_KEY_INT + i, -1);
        	if(position != -1) {
        		mPackageNamePositions.add(position);
        	}
        }
        
        if (isLaunching && PakaroidApplication.mApplications != null) {
        	ArrayList<ApplicationInfo> mApplications = PakaroidApplication.mApplications;
        	
        	for(int i = 0; i < mApplications.size(); i++) {
        		ApplicationInfo application = mApplications.get(i);
//                if(mPackageNames.contains(application.pakcageName)){
//            		Log.d(TAG, "loadApplications (match with apps): " + i + ", " + application.pakcageName);                	
//            		mLaunchApps.add(application);
//                }
                if(mPackageNamePositions.contains(i)){
            		Log.d(TAG, "loadApplications (match with apps): " + i + ", " + application.pakcageName);                	
            		mLaunchApps.add(application);
                }
            }
        }
        else {
            PackageManager manager = getPackageManager();

            Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

            final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
            Collections.sort(apps, new ResolveInfo.DisplayNameComparator(manager));

            if (apps != null) {
                final int count = apps.size();

            	ArrayList<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>(count);

                for (int i = 0; i < count; i++) {
                    ApplicationInfo application = new ApplicationInfo();
                    ResolveInfo info = apps.get(i);

                    application.title = info.loadLabel(manager);
                    application.pakcageName = info.activityInfo.packageName;
                    application.icon = info.activityInfo.loadIcon(manager);
            		application.setActivity(new ComponentName(
                            info.activityInfo.applicationInfo.packageName,
                            info.activityInfo.name),
                            Intent.FLAG_ACTIVITY_NEW_TASK
                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

//                    if(mPackageNames.contains(application.pakcageName)){
//                		Log.d(TAG, "loadApplications (match with apps): " + i + ", " + application.pakcageName);                	
//                        mLaunchApps.add(application);
//                    }
                    if(mPackageNamePositions.contains(i)){
                		Log.d(TAG, "loadApplications (match with apps): " + i + ", " + application.pakcageName);                	
                        mLaunchApps.add(application);
                    }
                    mApplications.add(application);
                }                
                PakaroidApplication.mApplications = mApplications;
            }
        }
    }
    
    /**
     * Adapter をセット
     */
    private void bindApplications() {
        if (mGrid == null) {
            mGrid = (GridView) findViewById(R.id.all_apps);
        }
        mGrid.setAdapter(new ApplicationsAdapter(this, mLaunchApps));
        mGrid.setSelection(0);
        
        if(mGrid.getAdapter().isEmpty()) {
			mShowAppBtn.setBackgroundResource(R.drawable.show_app_start_stateful);
		}
		else {
			if(mIsPlugged) {
				mShowAppBtn.setBackgroundResource(R.drawable.show_app_charge_stateful);
			}
			else {
				mShowAppBtn.setBackgroundResource(R.drawable.show_app_stateful);						
			}
		}
    }
    
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_BACK:
                    return true;
                case KeyEvent.KEYCODE_HOME:
                    return true;
            }
        } else if (event.getAction() == KeyEvent.ACTION_UP) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_BACK:
                    if (!event.isCanceled()) {
                        // Do BACK behavior.
                    }
                    return true;
                case KeyEvent.KEYCODE_HOME:
                    if (!event.isCanceled()) {
                        // Do HOME behavior.
                    }
                    return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }
    
    /**
     * アプリ一覧を表示
     */
    private void showApplications(boolean animate) {
        if (mBlockAnimation) {
            return;
        }
        mBlockAnimation = true;

        if (animate) {
            mGridEntry.setAnimationListener(new GridAnimationListener());
            mGrid.startAnimation(mGridEntry);
        }

        mGrid.setVisibility(View.VISIBLE);

        if (!animate) {
            mBlockAnimation = false;
        }
    }

    /**
     * アプリ一覧を非表示
     */
    private void hideApplications() {
        if (mBlockAnimation) {
            return;
        }
        mBlockAnimation = true;

        mGridExit.setAnimationListener(new GridAnimationListener());
        mGrid.startAnimation(mGridExit);
        mGrid.setVisibility(View.INVISIBLE);
        mShowAppBtn.requestFocus();
    }
    
    private class ShowWidget implements View.OnClickListener {
		@Override
		public void onClick(View v) {
            if (mWidgetContainer.getVisibility() != View.VISIBLE) {
                showWidgets(true);
            } else {
                hideWidgets();
            }				
		}    	
    }

    /**
     * 設定ウィジェットを表示
     */
    private void showWidgets(boolean animate) {
        if (mBlockAnimation2) {
            return;
        }
        mBlockAnimation2 = true;

        if (animate) {
            mTranslateEntry.setAnimationListener(new WidgetAnimationListener());
            mWidgetContainer.startAnimation(mTranslateEntry);
        }

        mWidgetContainer.setVisibility(View.VISIBLE);

        if (!animate) {
            mBlockAnimation2 = false;
        }
    }

    /**
     * 設定ウィジェットを非表示
     */
    private void hideWidgets() {
        if (mBlockAnimation2) {
            return;
        }
        mBlockAnimation2 = true;

        mTranslateExit.setAnimationListener(new WidgetAnimationListener());
        mWidgetContainer.startAnimation(mTranslateExit);
        mWidgetContainer.setVisibility(View.INVISIBLE);
        mShowWidgetBtn.requestFocus();
    }
        
    /**
     * GridView 用の Adapter
     */
    private class ApplicationsAdapter extends ArrayAdapter<ApplicationInfo> {
        private Rect mOldBounds = new Rect();

        public ApplicationsAdapter(Context context, ArrayList<ApplicationInfo> apps) {
            super(context, 0, apps);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final ApplicationInfo info = mLaunchApps.get(position);

            if (convertView == null) {
                final LayoutInflater inflater = getLayoutInflater();
                convertView = inflater.inflate(R.layout.application, parent, false);
            }

            Drawable icon = info.icon;

            if (!info.filtered) {
                //final Resources resources = getContext().getResources();
                int width = 74;//(int) resources.getDimension(android.R.dimen.app_icon_size);
                int height = 74;//(int) resources.getDimension(android.R.dimen.app_icon_size);

                final int iconWidth = icon.getIntrinsicWidth();
                final int iconHeight = icon.getIntrinsicHeight();

                if (icon instanceof PaintDrawable) {
                    PaintDrawable painter = (PaintDrawable) icon;
                    painter.setIntrinsicWidth(width);
                    painter.setIntrinsicHeight(height);
                }

                if (width > 0 && height > 0 && (width < iconWidth || height < iconHeight)) {
                    final float ratio = (float) iconWidth / iconHeight;

                    if (iconWidth > iconHeight) {
                        height = (int) (width / ratio);
                    } else if (iconHeight > iconWidth) {
                        width = (int) (height * ratio);
                    }

                    final Bitmap.Config c =
                            icon.getOpacity() == PixelFormat.OPAQUE ?
                            		Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888;
                    final Bitmap thumb = Bitmap.createBitmap(width, height, c);
                    final Canvas canvas = new Canvas(thumb);
                    canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, 0));
                    // Copy the old bounds to restore them later
                    // If we were to do oldBounds = icon.getBounds(),
                    // the call to setBounds() that follows would
                    // change the same instance and we would lose the
                    // old bounds
                    mOldBounds.set(icon.getBounds());
                    icon.setBounds(0, 0, width, height);
                    icon.draw(canvas);
                    icon.setBounds(mOldBounds);
                    icon = info.icon = new BitmapDrawable(thumb);
                    info.filtered = true;
                }
            }

            final TextView textView = (TextView) convertView.findViewById(R.id.label);
            textView.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
            textView.setText(info.title);

            return convertView;
        }
    }

    /**
     * Hides the applications grid when the layout animation is over.
     */
    private class GridAnimationListener implements Animation.AnimationListener {
        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {
            mBlockAnimation = false;
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }

    /**
     * Shows the applications grid when the layout animation is over.
     */
    private class WidgetAnimationListener implements Animation.AnimationListener {
        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {
            mBlockAnimation2 = false;
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }
}